home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / DirectPlay / VoicePosition / VoicePosition.cpp < prev    next >
C/C++ Source or Header  |  2001-10-31  |  80KB  |  1,953 lines

  1. //-----------------------------------------------------------------------------
  2. // File: VoicePosition.cpp
  3. //
  4. // Desc: The main file for VoicePosition that shows how use DirectPlay along 
  5. //       with DirectPlayVoice to allow talking in a conference situation. 
  6. //
  7. // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #define D3D_OVERLOADS
  11. #include <windows.h>
  12. #include <basetsd.h>
  13. #include <cguid.h>
  14. #include <stdio.h>
  15. #include <dxerr8.h>
  16. #include <d3dtypes.h>
  17. #include <dplay8.h>
  18. #include <dplobby8.h>
  19. #include <dvoice.h>
  20. #include <commctrl.h>
  21. #include <cguid.h>
  22. #include "NetConnect.h"
  23. #include "NetVoice.h"
  24. #include "DXUtil.h"
  25. #include "resource.h"
  26.  
  27.  
  28.  
  29.  
  30. //-----------------------------------------------------------------------------
  31. // Player context locking defines
  32. //-----------------------------------------------------------------------------
  33. CRITICAL_SECTION g_csPlayerContext;
  34. #define PLAYER_LOCK()                   EnterCriticalSection( &g_csPlayerContext ); 
  35. #define PLAYER_ADDREF( pPlayerInfo )    if( pPlayerInfo ) pPlayerInfo->lRefCount++;
  36. #define PLAYER_RELEASE( pPlayerInfo )   if( pPlayerInfo ) { pPlayerInfo->lRefCount--; if( pPlayerInfo->lRefCount <= 0 ) { DeleteCriticalSection( &pPlayerInfo->csPlayer ); SAFE_DELETE( pPlayerInfo );}  } pPlayerInfo = NULL;
  37. #define PLAYER_UNLOCK()                 LeaveCriticalSection( &g_csPlayerContext );
  38.  
  39.  
  40. //-----------------------------------------------------------------------------
  41. // Defines, and constants
  42. //-----------------------------------------------------------------------------
  43. #define DPLAY_SAMPLE_KEY        TEXT("Software\\Microsoft\\DirectX DirectPlay Samples")
  44. #define MAP_WIDTH               100
  45. #define MAP_HEIGHT              100
  46. #define MAX_PLAYER_NAME         14
  47. #define WM_APP_DISPLAY_PLAYERS  (WM_APP + 0)
  48. #define WM_APP_UPDATE_GRID      (WM_APP + 1)
  49. #define START_POSITION_X        ( MAP_WIDTH  / 2 )
  50. #define START_POSITION_Y        ( MAP_HEIGHT / 2 )
  51.  
  52. // This GUID allows DirectPlay to find other instances of the same game on
  53. // the network.  So it must be unique for every game, and the same for 
  54. // every instance of that game.  // {9363CC5D-F8BE-47cf-A288-E4DD73F0BCA6}
  55. GUID g_guidApp = { 0x9363cc5d, 0xf8be, 0x47cf, { 0xa2, 0x88, 0xe4, 0xdd, 0x73, 0xf0, 0xbc, 0xa6 } };
  56.  
  57. struct APP_PLAYER_INFO
  58. {
  59.     LONG         lRefCount;                        // Ref count so we can cleanup when all threads 
  60.                                                    // are done w/ this object
  61.     CRITICAL_SECTION csPlayer;                     // Critical section for DSB voice 
  62.     DPNID        dpnidPlayer;                      // dpnid of the player
  63.     BOOL         bTalking;                         // Is the player talking
  64.     BOOL         bHalfDuplex;                      // If true, then player cannot talk
  65.     POINT        pt;                               // Location of player
  66.     LPDIRECTSOUND3DBUFFER pDSBVoice;               // DirectSound 3D buffer for player
  67.     TCHAR        strPlayerName[MAX_PLAYER_NAME];   // Player name
  68. };
  69.  
  70.  
  71.  
  72.  
  73. //-----------------------------------------------------------------------------
  74. // App specific DirectPlay messages and structures 
  75. //-----------------------------------------------------------------------------
  76. #define GAME_MSGID_PLAYERMOVED      1
  77.  
  78. // Change compiler pack alignment to be BYTE aligned, and pop the current value
  79. #pragma pack( push, 1 )
  80.  
  81. struct GAMEMSG_GENERIC
  82. {
  83.     DWORD dwType;
  84. };
  85.  
  86. struct GAMEMSG_PLAYERMOVED : public GAMEMSG_GENERIC
  87. {
  88.     POINT pt;
  89. };
  90.  
  91. // Pop the old pack alignment
  92. #pragma pack( pop )
  93.  
  94.  
  95.  
  96. //-----------------------------------------------------------------------------
  97. // Global variables
  98. //-----------------------------------------------------------------------------
  99. HINSTANCE          g_hInst                       = NULL;    // HINST of app
  100. HWND               g_hDlg                        = NULL;    // HWND of main dialog
  101. IDirectPlay8Peer*  g_pDP                         = NULL;    // DirectPlay peer object
  102. CNetConnectWizard* g_pNetConnectWizard           = NULL;    // Connection wizard
  103. CNetVoice*         g_pNetVoice                   = NULL;    // DirectPlay voice helper class
  104. IDirectPlay8LobbiedApplication* g_pLobbiedApp    = NULL;    // DirectPlay lobbied app 
  105. BOOL               g_bWasLobbyLaunched           = FALSE;   // TRUE if lobby launched
  106. TCHAR              g_strAppName[256]             = TEXT("VoicePosition");
  107. APP_PLAYER_INFO*   g_pPlayerLocal                = NULL;    // APP_PLAYER_INFO* of local player
  108. BOOL               g_bVoiceSessionInProgress     = FALSE;   // True if voice has been init'ed
  109. DPNID*             g_pPlayers                    = NULL;    // Array of DPNIDs
  110. DWORD              g_dwPlayersArraySize          = 0;       // Size of g_pPlayers
  111. HRESULT            g_hrDialog;                              // Exit code for app 
  112. TCHAR              g_strLocalPlayerName[MAX_PATH];          // Local player name
  113. TCHAR              g_strSessionName[MAX_PATH];              // Session name
  114. TCHAR              g_strPreferredProvider[MAX_PATH];        // Provider string
  115. BOOL               g_bHostPlayer                 = FALSE;   // TRUE if local player is host
  116. DPNID              g_LocalPlayerDPNID            = 0;       // DPNID of local player
  117. GUID               g_guidDVSessionCT;                       // GUID for choosen voice compression
  118. DVCLIENTCONFIG     g_dvClientConfig;                        // Voice client config
  119. LPDIRECTSOUND3DLISTENER g_pDSListener            = NULL;    // DirectSound 3D listener
  120. LPDIRECTSOUND      g_pDS                         = NULL;    // DirectSound object
  121. HANDLE             g_hSoundInit                  = NULL;    // Signaled if DirectSound inited
  122.  
  123.  
  124.  
  125.  
  126. //-----------------------------------------------------------------------------
  127. // Function-prototypes
  128. //-----------------------------------------------------------------------------
  129. INT_PTR CALLBACK VoiceDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  130. HRESULT WINAPI   DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  131. HRESULT WINAPI   DirectPlayLobbyMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  132. HRESULT WINAPI   DirectPlayVoiceClientMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  133. HRESULT WINAPI   DirectPlayVoiceServerMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  134. HRESULT          InitDirectPlay();
  135. HRESULT          OnInitDialog( HWND hDlg );
  136. HRESULT          InitDirectSound( HWND hDlg );
  137. HRESULT          DisplayPlayersInChat( HWND hDlg );
  138. HRESULT          SendLocalPosition( HWND hDlg );
  139. VOID             DrawDotOnGrid( HWND hWndGrid, HDC hDC, BOOL bLocalDot, FLOAT fPosX, FLOAT fPosY );
  140. HRESULT          UpdateGrid( HWND hDlg );
  141. void             SetPlayerTalking( APP_PLAYER_INFO* pPlayerInfo, BOOL bTalking );
  142. INT_PTR CALLBACK VoiceConfigDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  143. HRESULT          VoiceConfigEnumCompressionCodecs( HWND hDlg );
  144. VOID             VoiceConfigDlgOnOK( HWND hDlg );
  145.  
  146.  
  147.  
  148.  
  149. //-----------------------------------------------------------------------------
  150. // Name: WinMain()
  151. // Desc: Entry point for the application.  Since we use a simple dialog for 
  152. //       user interaction we don't need to pump messages.
  153. //-----------------------------------------------------------------------------
  154. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, 
  155.                       INT nCmdShow )
  156. {
  157.     HRESULT hr;
  158.     HKEY    hDPlaySampleRegKey;
  159.     BOOL    bConnectSuccess = FALSE;
  160.  
  161.     g_hInst = hInst;
  162.     InitializeCriticalSection( &g_csPlayerContext );
  163.     g_hSoundInit = CreateEvent( NULL, TRUE, FALSE, NULL );
  164.  
  165.     // Init player ID array 
  166.     g_dwPlayersArraySize = 10;
  167.     g_pPlayers = (DPNID*) malloc( sizeof(DPNID)*g_dwPlayersArraySize );
  168.  
  169.     // Read persistent state information from registry
  170.     RegCreateKeyEx( HKEY_CURRENT_USER, DPLAY_SAMPLE_KEY, 0, NULL,
  171.                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
  172.                     &hDPlaySampleRegKey, NULL );
  173.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), 
  174.                              g_strLocalPlayerName, MAX_PATH, TEXT("TestPlayer") );
  175.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), 
  176.                              g_strSessionName, MAX_PATH, TEXT("TestGame") );
  177.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), 
  178.                              g_strPreferredProvider, MAX_PATH, TEXT("DirectPlay8 TCP/IP Service Provider") );
  179.  
  180.     InitCommonControls();
  181.  
  182.     // Init COM so we can use CoCreateInstance
  183.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  184.  
  185.     // Create helper class
  186.     g_pNetConnectWizard = new CNetConnectWizard( hInst, NULL, g_strAppName, &g_guidApp );
  187.     g_pNetVoice         = new CNetVoice( DirectPlayVoiceClientMessageHandler, DirectPlayVoiceServerMessageHandler );
  188.  
  189.     if( FAILED( hr = InitDirectPlay() ) )
  190.     {
  191.         DXTRACE_ERR( TEXT("InitDirectPlay"), hr );
  192.         MessageBox( NULL, TEXT("Failed initializing IDirectPlay8Peer. ")
  193.                     TEXT("The sample will now quit."),
  194.                     TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  195.         return FALSE;
  196.     }
  197.  
  198.     // Check if we were launched from a lobby client
  199.     if( g_bWasLobbyLaunched && g_pNetConnectWizard->HaveConnectionSettingsFromLobby() )
  200.     {
  201.         // If were lobby launched then DPL_MSGID_CONNECT has already been
  202.         // handled, so we can just tell the wizard to connect to the lobby
  203.         // that has sent us a DPL_MSGID_CONNECT msg.
  204.         if( FAILED( hr = g_pNetConnectWizard->ConnectUsingLobbySettings() ) )
  205.         {
  206.             DXTRACE_ERR( TEXT("ConnectUsingLobbySettings"), hr );
  207.             MessageBox( NULL, TEXT("Failed to connect using lobby settings. ")
  208.                         TEXT("The sample will now quit."),
  209.                         TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  210.  
  211.             bConnectSuccess = FALSE;
  212.         }
  213.         else
  214.         {
  215.             // Read information from g_pNetConnectWizard
  216.             _tcscpy( g_strLocalPlayerName, g_pNetConnectWizard->GetPlayerName() );
  217.             g_bHostPlayer = g_pNetConnectWizard->IsHostPlayer();
  218.  
  219.             bConnectSuccess = TRUE; 
  220.         }
  221.     }
  222.     else
  223.     {
  224.         // If not lobby launched, prompt the user about the network 
  225.         // connection and which session they would like to join or 
  226.         // if they want to create a new one.
  227.  
  228.         // Setup connection wizard
  229.         g_pNetConnectWizard->SetPlayerName( g_strLocalPlayerName );
  230.         g_pNetConnectWizard->SetSessionName( g_strSessionName );
  231.         g_pNetConnectWizard->SetPreferredProvider( g_strPreferredProvider );
  232.  
  233.         // Do the connection wizard
  234.         hr = g_pNetConnectWizard->DoConnectWizard( FALSE );        
  235.         if( FAILED( hr ) ) 
  236.         {
  237.             DXTRACE_ERR( TEXT("DoConnectWizard"), hr );        
  238.             MessageBox( NULL, TEXT("Multiplayer connect failed. ")
  239.                         TEXT("The sample will now quit."),
  240.                         TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  241.             bConnectSuccess = FALSE;
  242.         } 
  243.         else if( hr == NCW_S_QUIT ) 
  244.         {
  245.             // The user canceled the Multiplayer connect, so quit 
  246.             bConnectSuccess = FALSE;
  247.         }
  248.         else
  249.         {
  250.             bConnectSuccess = TRUE; 
  251.  
  252.             // Read information from g_pNetConnectWizard
  253.             _tcscpy( g_strLocalPlayerName, g_pNetConnectWizard->GetPlayerName() );
  254.             _tcscpy( g_strSessionName, g_pNetConnectWizard->GetSessionName() );
  255.             _tcscpy( g_strPreferredProvider, g_pNetConnectWizard->GetPreferredProvider() );
  256.             g_bHostPlayer = g_pNetConnectWizard->IsHostPlayer();
  257.  
  258.             // Write information to the registry
  259.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), g_strLocalPlayerName );
  260.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), g_strSessionName );
  261.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), g_strPreferredProvider );
  262.         }
  263.     }
  264.  
  265.     if( bConnectSuccess )
  266.     {
  267.         // Set default DirectPlayVoice setup options
  268.         ZeroMemory( &g_dvClientConfig, sizeof(g_dvClientConfig) );
  269.         g_dvClientConfig.dwSize                 = sizeof(g_dvClientConfig);
  270.         g_dvClientConfig.dwFlags                = DVCLIENTCONFIG_AUTOVOICEACTIVATED |
  271.                                                   DVCLIENTCONFIG_AUTORECORDVOLUME;
  272.         g_dvClientConfig.lPlaybackVolume        = DVPLAYBACKVOLUME_DEFAULT;
  273.         g_dvClientConfig.dwBufferQuality        = DVBUFFERQUALITY_DEFAULT;
  274.         g_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  275.         g_dvClientConfig.dwThreshold            = DVTHRESHOLD_UNUSED;
  276.         g_dvClientConfig.lRecordVolume          = DVRECORDVOLUME_LAST;
  277.         g_dvClientConfig.dwNotifyPeriod         = 0;
  278.  
  279.         g_guidDVSessionCT                       = DPVCTGUID_DEFAULT;
  280.  
  281.         // Ask the user for DirectPlayVoice setup params
  282.         DWORD dwResult = (DWORD)DialogBox( hInst, MAKEINTRESOURCE(IDD_VOICE_SETUP), 
  283.                                            NULL, VoiceConfigDlgProc );
  284.         if( dwResult != IDCANCEL )
  285.             g_pNetVoice->ChangeVoiceClientSettings( &g_dvClientConfig );
  286.     }
  287.  
  288.     if( bConnectSuccess )
  289.     {
  290.         // App is now connected via DirectPlay, so start the game.  
  291.  
  292.         // For this sample, we just start a simple dialog box game.
  293.         g_hrDialog = S_OK;
  294.         DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN_GAME), NULL, VoiceDlgProc );
  295.  
  296.         if( FAILED( g_hrDialog ) )
  297.         {
  298.             if( g_hrDialog == DPNERR_CONNECTIONLOST )
  299.             {
  300.                 MessageBox( NULL, TEXT("The DirectPlay session was lost. ")
  301.                             TEXT("The sample will now quit."),
  302.                             TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  303.             }
  304.             else
  305.             {
  306.                 DXTRACE_ERR( TEXT("DialogBox"), g_hrDialog );        
  307.                 MessageBox( NULL, TEXT("An error occured during the game. ")
  308.                             TEXT("The sample will now quit."),
  309.                             TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  310.             }
  311.         }
  312.     }
  313.     
  314.  
  315.     // Cleanup player ID array 
  316.     free( g_pPlayers );
  317.  
  318.     // Disconnect from the DirectPlayVoice session, 
  319.     // and destory it if we are the host player.
  320.     SAFE_DELETE( g_pNetVoice ); 
  321.  
  322.     // Cleanup DirectPlay and helper classes
  323.     g_pNetConnectWizard->Shutdown();
  324.  
  325.     if( g_pDP )
  326.     {
  327.         g_pDP->Close(0);
  328.         SAFE_RELEASE( g_pDP );
  329.     }
  330.  
  331.     if( g_pLobbiedApp )
  332.     {
  333.         g_pLobbiedApp->Close( 0 );
  334.         SAFE_RELEASE( g_pLobbiedApp );
  335.     }    
  336.  
  337.     // Don't delete the wizard until we know that 
  338.     // DirectPlay is out of its message handlers.
  339.     // This will be true after Close() has been called. 
  340.     SAFE_DELETE( g_pNetConnectWizard );
  341.  
  342.     // Release DirectSound interfaces
  343.     SAFE_RELEASE( g_pDSListener );
  344.     SAFE_RELEASE( g_pDS );
  345.  
  346.     RegCloseKey( hDPlaySampleRegKey );
  347.     CloseHandle( g_hSoundInit );
  348.     DeleteCriticalSection( &g_csPlayerContext );
  349.     CoUninitialize();
  350.  
  351.     return TRUE;
  352. }
  353.  
  354.  
  355.  
  356.  
  357. //-----------------------------------------------------------------------------
  358. // Name: InitDirectPlay()
  359. // Desc: 
  360. //-----------------------------------------------------------------------------
  361. HRESULT InitDirectPlay()
  362. {
  363.     DPNHANDLE hLobbyLaunchedConnection = NULL;
  364.     HRESULT hr;
  365.  
  366.     // Create IDirectPlay8Peer
  367.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL, 
  368.                                        CLSCTX_INPROC_SERVER,
  369.                                        IID_IDirectPlay8Peer, 
  370.                                        (LPVOID*) &g_pDP ) ) )
  371.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  372.  
  373.     // Create IDirectPlay8LobbiedApplication
  374.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8LobbiedApplication, NULL, 
  375.                                        CLSCTX_INPROC_SERVER,
  376.                                        IID_IDirectPlay8LobbiedApplication, 
  377.                                        (LPVOID*) &g_pLobbiedApp ) ) )
  378.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  379.  
  380.     // Init the helper class, now that g_pDP and g_pLobbiedApp are valid
  381.     g_pNetConnectWizard->Init( g_pDP, g_pLobbiedApp );
  382.  
  383.     // Init IDirectPlay8Peer
  384.     if( FAILED( hr = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) )
  385.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  386.  
  387.     // Init IDirectPlay8LobbiedApplication.  Before this Initialize() returns 
  388.     // a DPL_MSGID_CONNECT msg may come in to the DirectPlayLobbyMessageHandler 
  389.     // so be prepared ahead of time.
  390.     if( FAILED( hr = g_pLobbiedApp->Initialize( NULL, DirectPlayLobbyMessageHandler, 
  391.                                                 &hLobbyLaunchedConnection, 0 ) ) )
  392.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  393.  
  394.     // IDirectPlay8LobbiedApplication::Initialize returns a handle to a connnection
  395.     // if we have been lobby launced.  Initialize is guanteeded to return after 
  396.     // the DPL_MSGID_CONNECT msg has been processed.  So unless a we are expected 
  397.     // multiple lobby connections, we do not need to remember the lobby connection
  398.     // handle since it will be recorded upon the DPL_MSGID_CONNECT msg.
  399.     g_bWasLobbyLaunched = ( hLobbyLaunchedConnection != NULL );
  400.  
  401.     return S_OK;
  402. }
  403.  
  404.  
  405.  
  406.  
  407. //-----------------------------------------------------------------------------
  408. // Name: VoiceDlgProc()
  409. // Desc: Handles dialog messages
  410. //-----------------------------------------------------------------------------
  411. INT_PTR CALLBACK VoiceDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  412. {
  413.     switch( msg ) 
  414.     {
  415.         case WM_INITDIALOG:
  416.             {
  417.                 if( FAILED( g_hrDialog = OnInitDialog( hDlg ) ) )
  418.                 {
  419.                     DXTRACE_ERR( TEXT("OnInitDialog"), g_hrDialog );        
  420.                     EndDialog( hDlg, 0 );
  421.                     break;
  422.                 }
  423.  
  424.                 g_hDlg = hDlg;
  425.  
  426.                 if( FAILED( g_hrDialog = g_pNetVoice->Init( hDlg, g_bHostPlayer, TRUE,
  427.                                                             g_pDP, DVSESSIONTYPE_PEER, 
  428.                                                             &g_guidDVSessionCT, &g_dvClientConfig, g_pDS ) ) )
  429.                 {
  430.                     if( g_hrDialog == DVERR_USERBACK )
  431.                     {
  432.                         MessageBox( hDlg, TEXT("The user backed out of the wizard.  ")
  433.                                     TEXT("This simple sample does not handle this case, so ")
  434.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  435.                         g_hrDialog = S_OK;
  436.                     }
  437.  
  438.                     if( g_hrDialog == DVERR_USERCANCEL )
  439.                     {
  440.                         MessageBox( hDlg, TEXT("The user canceled the wizard. ")
  441.                                     TEXT("This simple sample does not handle this case, so ")
  442.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  443.                         g_hrDialog = S_OK;
  444.                     }
  445.  
  446.                     if( g_hrDialog == DVERR_ALREADYPENDING )
  447.                     {
  448.                         MessageBox( hDlg, TEXT("Another instance of the Voice Setup Wizard is already running. ")
  449.                                     TEXT("This simple sample does not handle this case, so ")
  450.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  451.                         g_hrDialog = S_OK;
  452.                     }
  453.  
  454.                     if( FAILED(g_hrDialog) )
  455.                         DXTRACE_ERR( TEXT("Init"), g_hrDialog );        
  456.  
  457.                     EndDialog( hDlg, 0 );
  458.                     break;
  459.                 }
  460.  
  461.                 if( g_pNetVoice->IsHalfDuplex() ) 
  462.                 {
  463.                     MessageBox( hDlg, TEXT("You are running in half duplex mode. ")
  464.                                 TEXT("In half duplex mode no recording takes place."), 
  465.                                 TEXT("DirectPlay Sample"), MB_OK );
  466.                 }
  467.  
  468.                 g_bVoiceSessionInProgress = TRUE;
  469.             }
  470.             break;
  471.  
  472.         case WM_COMMAND:
  473.             switch( LOWORD(wParam) )
  474.             {
  475.                 case IDC_SETUP:
  476.                     {
  477.                         // Ask the user for DirectPlayVoice setup params
  478.                         DWORD dwResult = (DWORD)DialogBox( g_hInst, 
  479.                                                            MAKEINTRESOURCE(IDD_VOICE_SETUP), 
  480.                                                            hDlg, VoiceConfigDlgProc );
  481.                         if( dwResult != IDCANCEL )
  482.                             g_pNetVoice->ChangeVoiceClientSettings( &g_dvClientConfig );
  483.                     }
  484.                     return TRUE;
  485.  
  486.                 case IDCANCEL:
  487.                     g_hrDialog = S_OK;
  488.                     EndDialog( hDlg, 0 );
  489.                     return TRUE;
  490.             }
  491.             break;
  492.  
  493.         case WM_APP_DISPLAY_PLAYERS:
  494.         {
  495.             DisplayPlayersInChat( hDlg );
  496.             break;
  497.         }
  498.  
  499.         case WM_APP_UPDATE_GRID:
  500.         {
  501.             UpdateGrid( hDlg );
  502.             break;
  503.         }
  504.  
  505.         case WM_TIMER:
  506.         {
  507.             DWORD            dwNumPlayers;
  508.             DWORD            iIndex;
  509.             LVITEM           lvItem;
  510.             APP_PLAYER_INFO* pPlayerInfo = NULL;
  511.             HWND             hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  512.  
  513.             dwNumPlayers = ListView_GetItemCount( hListView );
  514.  
  515.             // Now that they are added and the listview sorted them by name,
  516.             // run through them all caching the listview index with its dpnid
  517.             for( iIndex = 0; iIndex < dwNumPlayers; iIndex++ )
  518.             {
  519.                 HRESULT hr;
  520.                 APP_PLAYER_INFO* pPlayerInfo = NULL;
  521.                 DPNID dpnidPlayer;
  522.  
  523.                 lvItem.mask  = LVIF_PARAM;
  524.                 lvItem.iItem = iIndex;
  525.                 ListView_GetItem( hListView, &lvItem );
  526.  
  527.                 dpnidPlayer = (DPNID) lvItem.lParam;
  528.  
  529.                 PLAYER_LOCK(); // enter player context CS
  530.  
  531.                 // Get the player context accosicated with this DPNID
  532.                 hr = g_pDP->GetPlayerContext( dpnidPlayer, 
  533.                                               (LPVOID* const) &pPlayerInfo,
  534.                                               0);
  535.  
  536.  
  537.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  538.                 PLAYER_UNLOCK(); // leave player context CS
  539.  
  540.                 if( FAILED(hr) || pPlayerInfo == NULL )
  541.                 {
  542.                     // The player who sent this may have gone away before this 
  543.                     // message was handled, so just ignore it
  544.                     continue;
  545.                 }
  546.  
  547.                 TCHAR strStatus[255];
  548.  
  549.                 if( pPlayerInfo->bHalfDuplex )
  550.                 {
  551.                     _tcscpy( strStatus, TEXT("Can't talk") );
  552.                 }
  553.                 else
  554.                 {
  555.                     if( pPlayerInfo->bTalking )
  556.                         _tcscpy( strStatus, TEXT("Talking") );
  557.                     else
  558.                         _tcscpy( strStatus, TEXT("Silent") );
  559.                 }
  560.  
  561.                 lvItem.iItem      = iIndex;
  562.                 lvItem.iSubItem   = 1;
  563.                 lvItem.mask       = LVIF_TEXT;
  564.                 lvItem.pszText    = strStatus;
  565.  
  566.                 PLAYER_LOCK();
  567.                 PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  568.                 PLAYER_UNLOCK();
  569.  
  570.                 SendMessage( hListView, LVM_SETITEM, 0, (LPARAM) &lvItem );
  571.             }
  572.             break;
  573.         }
  574.  
  575.         case WM_PAINT:
  576.         {
  577.             DWORD            dwNumPlayers;
  578.             DWORD            iIndex;
  579.             LVITEM           lvItem;
  580.             APP_PLAYER_INFO* pPlayerInfo  = NULL;
  581.             HWND             hListView    = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  582.             HWND             hWndGrid     = GetDlgItem( hDlg, IDC_RENDER_WINDOW );
  583.             BOOL             bIsLocalPlayer;
  584.  
  585.             // Erase and redraw the grid window right now
  586.             RedrawWindow( hWndGrid, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | 
  587.                                                 RDW_INTERNALPAINT | RDW_UPDATENOW );
  588.             HDC hDC = GetDC( hWndGrid );
  589.  
  590.             dwNumPlayers = ListView_GetItemCount( hListView );
  591.  
  592.             // Now that they are added and the listview sorted them by name,
  593.             // run through them all caching the listview index with its dpnid
  594.             for( iIndex = 0; iIndex < dwNumPlayers; iIndex++ )
  595.             {
  596.                 HRESULT hr;
  597.                 APP_PLAYER_INFO* pPlayerInfo = NULL;
  598.                 DPNID dpnidPlayer;
  599.  
  600.                 lvItem.mask  = LVIF_PARAM;
  601.                 lvItem.iItem = iIndex;
  602.                 ListView_GetItem( hListView, &lvItem );
  603.  
  604.                 dpnidPlayer = (DPNID) lvItem.lParam;
  605.  
  606.                 PLAYER_LOCK(); // enter player context CS
  607.  
  608.                 // Get the player context accosicated with this DPNID
  609.                 hr = g_pDP->GetPlayerContext( dpnidPlayer, 
  610.                                               (LPVOID* const) &pPlayerInfo,
  611.                                               0);
  612.  
  613.  
  614.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  615.                 PLAYER_UNLOCK(); // leave player context CS
  616.  
  617.                 if( FAILED(hr) || pPlayerInfo == NULL )
  618.                 {
  619.                     // The player who sent this may have gone away before this 
  620.                     // message was handled, so just ignore it
  621.                     continue;
  622.                 }
  623.  
  624.                 if( pPlayerInfo->dpnidPlayer == g_LocalPlayerDPNID )
  625.                     bIsLocalPlayer = TRUE;
  626.                 else
  627.                     bIsLocalPlayer = FALSE;
  628.                 
  629.                 DrawDotOnGrid( hWndGrid, hDC, bIsLocalPlayer,
  630.                                pPlayerInfo->pt.x / (float) MAP_WIDTH, 
  631.                                pPlayerInfo->pt.y / (float) MAP_HEIGHT );
  632.  
  633.                 PLAYER_LOCK();
  634.                 PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  635.                 PLAYER_UNLOCK();
  636.                 
  637.             }
  638.  
  639.             ReleaseDC( hWndGrid, hDC );    
  640.             break;
  641.         }
  642.  
  643.         case WM_NOTIFY:
  644.             {
  645.                 LPNMLISTVIEW pnm = (LPNMLISTVIEW)lParam;
  646.  
  647.                 if( pnm->hdr.code == NM_CUSTOMDRAW &&
  648.                     (pnm->hdr.idFrom == IDC_VERTICAL_SLIDER || pnm->hdr.idFrom == IDC_HORIZONTAL_SLIDER) )
  649.                 {
  650.                     LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
  651.  
  652.                     if( lplvcd->nmcd.dwDrawStage == CDDS_PREPAINT )
  653.                     {
  654.                         POINT pt;
  655.  
  656.                         pt.x = (LONG)SendDlgItemMessage( hDlg, IDC_HORIZONTAL_SLIDER, TBM_GETPOS, 0, 0 );
  657.                         pt.y = (LONG)SendDlgItemMessage( hDlg, IDC_VERTICAL_SLIDER,   TBM_GETPOS, 0, 0 );
  658.  
  659.                         if( NULL == g_pPlayerLocal )
  660.                             return CDRF_DODEFAULT;
  661.  
  662.                         // Don't do anything if nothing has changed.
  663.                         if( pt.x != g_pPlayerLocal->pt.x || pt.y != g_pPlayerLocal->pt.y )
  664.                         {
  665.                             // Don't send the position too fast, otherwise it will
  666.                             // slow down the network link 
  667.                             static DWORD s_dwLastSendTime = 0;
  668.                             DWORD dwCurTime = timeGetTime();
  669.                             if( dwCurTime - s_dwLastSendTime > 50 )
  670.                             {
  671.                                 s_dwLastSendTime = dwCurTime;
  672.                                 g_pPlayerLocal->pt = pt;
  673.  
  674.                                 if( FAILED( g_hrDialog = SendLocalPosition( hDlg ) ) )
  675.                                 {
  676.                                     DXTRACE_ERR( TEXT("SendLocalPosition"), g_hrDialog );        
  677.                                     MessageBox( hDlg, TEXT("Error updating the local position.  ")
  678.                                                 TEXT("Sample will now exit."), TEXT("DirectPlayVoice Sample"), 
  679.                                                 MB_OK | MB_ICONERROR );
  680.                                     EndDialog( hDlg, 0 );
  681.                                 }
  682.  
  683.                                 // Update the grid
  684.                                 PostMessage( hDlg, WM_APP_UPDATE_GRID, 0, 0 );
  685.                             }
  686.                         }
  687.  
  688.                         return CDRF_DODEFAULT;
  689.                     }
  690.                 }
  691.             }
  692.             break;
  693.  
  694.         case WM_LBUTTONDOWN:
  695.             {
  696.                 POINT pt;
  697.                 RECT  rc;
  698.                 HWND  hWndGrid = GetDlgItem( hDlg, IDC_RENDER_WINDOW );
  699.  
  700.                 // Check to see if the click was inside the map position window
  701.                 // if it was then move the position there
  702.                 pt.x = LOWORD( lParam );
  703.                 pt.y = HIWORD( lParam );
  704.  
  705.                 ClientToScreen( hDlg, &pt );
  706.                 ScreenToClient( hWndGrid, &pt );
  707.                 GetClientRect( hWndGrid, &rc );
  708.  
  709.                 if( pt.x > rc.left && pt.x < rc.right &&
  710.                     pt.y > rc.top  && pt.y < rc.bottom )
  711.                 {
  712.                     // Set the position, but do it careful since we check the 
  713.                     // slider position's whenever a slider is redrawn, so 
  714.                     // be careful when the sliders are redrawn otherwise false
  715.                     // position messages will be sent to everyone in the session
  716.                     g_pPlayerLocal->pt.x = pt.x;
  717.                     SendDlgItemMessage( hDlg, IDC_HORIZONTAL_SLIDER, TBM_SETPOS, TRUE, pt.x );
  718.                     g_pPlayerLocal->pt.y = pt.y;
  719.                     SendDlgItemMessage( hDlg, IDC_VERTICAL_SLIDER, TBM_SETPOS, TRUE, pt.y );
  720.  
  721.                     if( FAILED( g_hrDialog = SendLocalPosition( hDlg ) ) )
  722.                     {
  723.                         DXTRACE_ERR( TEXT("SendLocalPosition"), g_hrDialog );        
  724.                         MessageBox( hDlg, TEXT("Error updating the local position.  ")
  725.                                     TEXT("Sample will now exit."), TEXT("DirectPlayVoice Sample"), 
  726.                                     MB_OK | MB_ICONERROR );
  727.                         EndDialog( g_hDlg, 0 );
  728.                     }   
  729.  
  730.                     // Update the grid
  731.                     PostMessage( hDlg, WM_APP_UPDATE_GRID, 0, 0 );
  732.                 }
  733.             }
  734.             break;
  735.     }
  736.  
  737.     return FALSE; // Didn't handle message
  738. }
  739.  
  740.  
  741.  
  742.  
  743. //-----------------------------------------------------------------------------
  744. // Name: OnInitDialog()
  745. // Desc: Inits the dialog 
  746. //-----------------------------------------------------------------------------
  747. HRESULT OnInitDialog( HWND hDlg )
  748. {
  749.     HRESULT  hr;
  750.     LVCOLUMN column;
  751.     RECT     rctListView;
  752.     TCHAR    strHeader[255];
  753.     DWORD    dwVertScrollBar;
  754.     DWORD    dwListViewWidth;
  755.  
  756.     // Setup DirectSound, and the 3D listener
  757.     if( FAILED( hr = InitDirectSound( hDlg ) ) )
  758.         return hr;
  759.  
  760.     // Load and set the icon
  761.     HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  762.     SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  763.     SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  764.  
  765.     if( g_bHostPlayer )
  766.         SetWindowText( hDlg, TEXT("VoicePosition (Session Host)") );
  767.     else
  768.         SetWindowText( hDlg, TEXT("VoicePosition (Session Client)") );
  769.  
  770.     // Setup the listview
  771.     HWND hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  772.     dwVertScrollBar = GetSystemMetrics( SM_CXVSCROLL );  
  773.     GetClientRect( hListView, &rctListView );
  774.     dwListViewWidth = rctListView.right - dwVertScrollBar;
  775.     column.mask     = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
  776.     column.fmt      = LVCFMT_LEFT;
  777.     column.iSubItem = -1;
  778.  
  779.     // Insert the Name column
  780.     _tcscpy( strHeader, TEXT("Name") );
  781.     column.cx         = dwListViewWidth * 5 / 10;
  782.     column.pszText    = strHeader;
  783.     column.cchTextMax = _tcslen( strHeader );
  784.     ListView_InsertColumn( hListView, 0, &column );
  785.  
  786.     // Insert the Status column
  787.     _tcscpy( strHeader, TEXT("Status") );
  788.     column.cx         = dwListViewWidth * 5 / 10;
  789.     column.pszText    = strHeader;
  790.     column.cchTextMax = _tcslen( strHeader );
  791.     ListView_InsertColumn( hListView, 1, &column );
  792.  
  793.     SendDlgItemMessage( hDlg, IDC_HORIZONTAL_SLIDER, TBM_SETRANGE, 0, MAKELONG( 0, MAP_WIDTH ) );
  794.     SendDlgItemMessage( hDlg, IDC_VERTICAL_SLIDER,   TBM_SETRANGE, 0, MAKELONG( 0, MAP_HEIGHT ) );
  795.  
  796.     SendDlgItemMessage( hDlg, IDC_HORIZONTAL_SLIDER, TBM_SETPOS, TRUE, START_POSITION_X );
  797.     SendDlgItemMessage( hDlg, IDC_VERTICAL_SLIDER,   TBM_SETPOS, TRUE, START_POSITION_Y );
  798.  
  799.     // Send the local players postion to everyone
  800.     if( FAILED( hr = SendLocalPosition( hDlg ) ) ) 
  801.         return DXTRACE_ERR( TEXT("SendLocalPosition"), hr );        
  802.  
  803.     // Update the listbox 
  804.     PostMessage( hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  805.  
  806.     // Update the grid
  807.     PostMessage( hDlg, WM_APP_UPDATE_GRID, 0, 0 );
  808.  
  809.     // Make a timer to update the listbox 
  810.     // 'Status' column every so often 
  811.     SetTimer( hDlg, 0, 250, NULL );
  812.  
  813.     return S_OK;
  814. }
  815.  
  816.  
  817.  
  818.  
  819. //-----------------------------------------------------------------------------
  820. // Name: InitDirectSound()
  821. // Desc: Initializes DirectSound
  822. //-----------------------------------------------------------------------------
  823. HRESULT InitDirectSound( HWND hDlg )
  824. {
  825.     HRESULT hr;
  826.   
  827.     if( FAILED( hr = DirectSoundCreate( &DSDEVID_DefaultVoicePlayback, &g_pDS, NULL ) ) )
  828.         return DXTRACE_ERR( TEXT("DirectSoundCreate"), hr );        
  829.  
  830.     if( FAILED( hr = g_pDS->SetCooperativeLevel( hDlg, DSSCL_PRIORITY ) ) )
  831.         return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );        
  832.  
  833.     // Obtain primary buffer, asking it for 3D control
  834.     DSBUFFERDESC        dsbd;
  835.     LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
  836.  
  837.     ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
  838.     dsbd.dwSize  = sizeof(DSBUFFERDESC);
  839.     dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
  840.     if( FAILED( hr = g_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
  841.         return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );        
  842.  
  843.     if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener, 
  844.                                                   (VOID**)&g_pDSListener ) ) )
  845.         return DXTRACE_ERR( TEXT("QueryInterface"), hr );        
  846.  
  847.     // Done with the primary buffer, so release it
  848.     SAFE_RELEASE( pDSBPrimary );
  849.  
  850.     DS3DLISTENER dslsn;
  851.     ZeroMemory( &dslsn, sizeof(dslsn) );
  852.  
  853.     dslsn.dwSize = sizeof(dslsn);
  854.     dslsn.flDistanceFactor = 1.0f;  // All DSound3D units are in meters
  855.     dslsn.flDopplerFactor  = DS3D_DEFAULTDOPPLERFACTOR;
  856.  
  857.     // Use 3 times the real rolloff factor so that 
  858.     // the voices don't fade away too quickly
  859.     dslsn.flRolloffFactor  = 3.0f; 
  860.     dslsn.vOrientFront     = D3DVECTOR( 0.0f, 0.0f, 1.0f );
  861.     dslsn.vOrientTop       = D3DVECTOR( 0.0f, 1.0f, 0.0f );
  862.     dslsn.vPosition        = D3DVECTOR( 0.0f, 0.0f, 0.0f );
  863.     dslsn.vVelocity        = D3DVECTOR( 0.0f, 0.0f, 0.0f );
  864.  
  865.     if( FAILED( hr = g_pDSListener->SetAllParameters( &dslsn, DS3D_IMMEDIATE ) ) ) 
  866.         return DXTRACE_ERR( TEXT("SetAllParameters"), hr );        
  867.  
  868.     SetEvent( g_hSoundInit );
  869.  
  870.     return S_OK;
  871. }
  872.  
  873.  
  874.  
  875.  
  876. //-----------------------------------------------------------------------------
  877. // Name: SendLocalPosition()
  878. // Desc: Updates the local position, and sends the new position to all the players 
  879. //-----------------------------------------------------------------------------
  880. HRESULT SendLocalPosition( HWND hDlg )
  881. {
  882.     if( g_pPlayerLocal == NULL )
  883.         return S_OK;
  884.  
  885.     GAMEMSG_PLAYERMOVED msgPlayerMoved;
  886.     msgPlayerMoved.dwType = GAME_MSGID_PLAYERMOVED;
  887.     msgPlayerMoved.pt     = g_pPlayerLocal->pt;
  888.  
  889.     DPN_BUFFER_DESC bufferDesc;
  890.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_PLAYERMOVED);
  891.     bufferDesc.pBufferData  = (BYTE*) &msgPlayerMoved;
  892.  
  893.     // Send it to all of the players
  894.     // DirectPlay will tell via the message handler 
  895.     // if there are any severe errors, so ignore any errors 
  896.     DPNHANDLE hAsync;
  897.     g_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1, 
  898.                    0, NULL, &hAsync, DPNSEND_NOLOOPBACK | DPNSEND_GUARANTEED );
  899.  
  900.     return S_OK;
  901. }
  902.  
  903.  
  904.  
  905.  
  906. //-----------------------------------------------------------------------------
  907. // Name: DisplayPlayersInChat()
  908. // Desc: Displays the active players in the listview
  909. //-----------------------------------------------------------------------------
  910. HRESULT DisplayPlayersInChat( HWND hDlg )
  911. {
  912.     if( hDlg == NULL )
  913.         return S_OK;
  914.  
  915.     HRESULT hr;
  916.     LVITEM  lvItem;
  917.     HWND    hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  918.     TCHAR   strStatus[32];
  919.     TCHAR   strNumberPlayers[32];
  920.     DWORD   dwNumPlayers;
  921.     APP_PLAYER_INFO* pPlayerInfo = NULL;
  922.  
  923.     // Remove all the players and re-add them in the player enum callback
  924.     ListView_DeleteAllItems( hListView );
  925.  
  926.     do
  927.     {
  928.         // Enum all players in the player ID array
  929.         dwNumPlayers = g_dwPlayersArraySize;
  930.         hr = g_pDP->EnumPlayersAndGroups( g_pPlayers, &dwNumPlayers, DPNENUM_PLAYERS );
  931.         if( SUCCEEDED(hr) )
  932.             break;
  933.  
  934.         if( hr == DPNERR_BUFFERTOOSMALL )
  935.         {
  936.             // Resize player pointer array     
  937.             g_dwPlayersArraySize += 10;
  938.             g_pPlayers = (DPNID*) realloc( g_pPlayers, sizeof(DPNID)*g_dwPlayersArraySize );
  939.         }
  940.     } 
  941.     while( hr == DPNERR_BUFFERTOOSMALL );
  942.     if( FAILED(hr) )
  943.         return DXTRACE_ERR( TEXT("EnumPlayersAndGroups"), hr );        
  944.  
  945.     for( DWORD i = 0; i<dwNumPlayers; i++ )
  946.     {
  947.         PLAYER_LOCK(); // enter player context CS
  948.  
  949.         do
  950.         {
  951.             // Get the player context accosicated with this DPNID
  952.             // Call GetPlayerContext() until it returns something other than DPNERR_NOTREADY
  953.             // DPNERR_NOTREADY will be returned if the callback thread has not 
  954.             // yet returned from DPN_MSGID_CREATE_PLAYER, which sets the player's context
  955.             hr = g_pDP->GetPlayerContext( g_pPlayers[i], (LPVOID*) &pPlayerInfo, 0);
  956.         } 
  957.         while( hr == DPNERR_NOTREADY ); 
  958.  
  959.         PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  960.         PLAYER_UNLOCK(); // leave player context CS
  961.  
  962.         if( FAILED(hr) || pPlayerInfo == NULL )
  963.         {
  964.             // The player who sent this may have gone away before this 
  965.             // message was handled, so just ignore it
  966.             continue;
  967.         }
  968.  
  969.         ZeroMemory( &lvItem, sizeof(lvItem) );
  970.  
  971.         // Add the item, saving the player's name and dpnid in the listview
  972.         lvItem.mask       = LVIF_TEXT | LVIF_PARAM;
  973.         lvItem.iItem      = 0;
  974.         lvItem.iSubItem   = 0;
  975.         lvItem.pszText    = pPlayerInfo->strPlayerName;
  976.         lvItem.lParam     = g_pPlayers[i];
  977.         lvItem.cchTextMax = _tcslen( pPlayerInfo->strPlayerName );
  978.         int nIndex = ListView_InsertItem( hListView, &lvItem );
  979.  
  980.         if( pPlayerInfo->bHalfDuplex )
  981.         {
  982.             _tcscpy( strStatus, TEXT("Can't talk") );
  983.         }
  984.         else
  985.         {
  986.             if( pPlayerInfo->bTalking )
  987.                 _tcscpy( strStatus, TEXT("Talking") );
  988.             else
  989.                 _tcscpy( strStatus, TEXT("Silent") );
  990.         }        
  991.  
  992.         PLAYER_LOCK();
  993.         PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  994.         PLAYER_UNLOCK();
  995.  
  996.         // Start the player's status off as silent.  
  997.         lvItem.mask       = LVIF_TEXT;
  998.         lvItem.iItem      = nIndex;
  999.         lvItem.iSubItem   = 1;
  1000.         lvItem.pszText    = strStatus;
  1001.         lvItem.cchTextMax = _tcslen( strStatus );
  1002.         ListView_SetItem( hListView, &lvItem );
  1003.     }
  1004.  
  1005.     wsprintf( strNumberPlayers, TEXT("%d"), dwNumPlayers );
  1006.     SetDlgItemText( hDlg, IDC_NUM_PLAYERS, strNumberPlayers );
  1007.  
  1008.     return S_OK;
  1009. }
  1010.  
  1011.  
  1012.  
  1013.  
  1014. //-----------------------------------------------------------------------------
  1015. // Name: UpdateGrid()
  1016. // Desc: Draws all the dots on dialog's grid bitmap 
  1017. //-----------------------------------------------------------------------------
  1018. HRESULT UpdateGrid( HWND hDlg )
  1019. {
  1020.     HRESULT hr;
  1021.     DWORD   dwNumPlayers;
  1022.     APP_PLAYER_INFO* pPlayerInfo = NULL;
  1023.  
  1024.     if( hDlg == NULL )
  1025.         return S_OK;
  1026.  
  1027.     HWND hWndGrid = GetDlgItem( hDlg, IDC_RENDER_WINDOW );
  1028.  
  1029.     // Erase and redraw the grid window right now
  1030.     RedrawWindow( hWndGrid, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | 
  1031.                                         RDW_INTERNALPAINT | RDW_UPDATENOW );
  1032.     HDC hDC = GetDC( hWndGrid );
  1033.  
  1034.     do
  1035.     {
  1036.         // Enum all players in the player ID array
  1037.         dwNumPlayers = g_dwPlayersArraySize;
  1038.         hr = g_pDP->EnumPlayersAndGroups( g_pPlayers, &dwNumPlayers, DPNENUM_PLAYERS );
  1039.         if( SUCCEEDED(hr) )
  1040.             break;
  1041.  
  1042.         if( hr == DPNERR_BUFFERTOOSMALL )
  1043.         {
  1044.             // Resize player pointer array     
  1045.             g_dwPlayersArraySize += 10;
  1046.             g_pPlayers = (DPNID*) realloc( g_pPlayers, g_dwPlayersArraySize );
  1047.         }
  1048.     } 
  1049.     while( hr == DPNERR_BUFFERTOOSMALL );
  1050.     if( FAILED(hr) )
  1051.         return DXTRACE_ERR( TEXT("EnumPlayersAndGroups"), hr );        
  1052.  
  1053.     for( DWORD i = 0; i<dwNumPlayers; i++ )
  1054.     {
  1055.         PLAYER_LOCK(); // enter player context CS
  1056.  
  1057.         do
  1058.         {
  1059.             // Get the player context accosicated with this DPNID
  1060.             // Call GetPlayerContext() until it returns something other than DPNERR_NOTREADY
  1061.             // DPNERR_NOTREADY will be returned if the callback thread has not 
  1062.             // yet returned from DPN_MSGID_CREATE_PLAYER, which sets the player's context
  1063.             hr = g_pDP->GetPlayerContext( g_pPlayers[i], (LPVOID*) &pPlayerInfo, 0);
  1064.         } 
  1065.         while( hr == DPNERR_NOTREADY ); 
  1066.  
  1067.         PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  1068.         PLAYER_UNLOCK(); // leave player context CS
  1069.  
  1070.         if( FAILED(hr) || pPlayerInfo == NULL )
  1071.         {
  1072.             // The player who sent this may have gone away before this 
  1073.             // message was handled, so just ignore it
  1074.             continue;
  1075.         }
  1076.  
  1077.         EnterCriticalSection( &pPlayerInfo->csPlayer );
  1078.  
  1079.         FLOAT f3DPosX = (FLOAT) ( pPlayerInfo->pt.x - START_POSITION_X ) / 10.0f;
  1080.         FLOAT f3DPosZ = (FLOAT) ( pPlayerInfo->pt.y - START_POSITION_Y ) / 10.0f;
  1081.  
  1082.         if( pPlayerInfo->dpnidPlayer == g_LocalPlayerDPNID )
  1083.         {
  1084.             DrawDotOnGrid( hWndGrid, hDC, TRUE,
  1085.                            pPlayerInfo->pt.x / (float) MAP_WIDTH, 
  1086.                            pPlayerInfo->pt.y / (float) MAP_HEIGHT );
  1087.  
  1088.             if( g_pDSListener ) 
  1089.             {
  1090.                 if( FAILED( hr = g_pDSListener->SetPosition( f3DPosX, 0.0f, 
  1091.                                                              f3DPosZ, DS3D_DEFERRED ) ) ) 
  1092.                     return DXTRACE_ERR( TEXT("SetPosition"), hr );        
  1093.  
  1094.                 DXUtil_Trace( TEXT("Setting listener to (%0.1ff,0.0f,%0.1ff)\n"), 
  1095.                               f3DPosX, f3DPosZ );
  1096.             }
  1097.         }
  1098.         else
  1099.         {
  1100.             DrawDotOnGrid( hWndGrid, hDC, FALSE,
  1101.                            pPlayerInfo->pt.x / (float) MAP_WIDTH, 
  1102.                            pPlayerInfo->pt.y / (float) MAP_HEIGHT );
  1103.  
  1104.             if( pPlayerInfo->pDSBVoice )
  1105.             {
  1106.                 if( FAILED( hr = pPlayerInfo->pDSBVoice->SetPosition( f3DPosX, 0.0f, 
  1107.                                                                 f3DPosZ, DS3D_DEFERRED ) ) ) 
  1108.                     return DXTRACE_ERR( TEXT("SetPosition"), hr );        
  1109.  
  1110.                 DXUtil_Trace( TEXT("Setting player 0x%0.8x to (%0.1ff,0.0f,%0.1ff)\n"), 
  1111.                               pPlayerInfo->dpnidPlayer, f3DPosX, f3DPosZ );
  1112.             }
  1113.         }
  1114.  
  1115.         LeaveCriticalSection( &pPlayerInfo->csPlayer );
  1116.  
  1117.         PLAYER_LOCK();
  1118.         PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1119.         PLAYER_UNLOCK();
  1120.         
  1121.     }
  1122.  
  1123.     ReleaseDC( hWndGrid, hDC );    
  1124.  
  1125.     if( g_pDSListener )
  1126.         g_pDSListener->CommitDeferredSettings();
  1127.  
  1128.     return S_OK;
  1129. }
  1130.  
  1131.  
  1132.  
  1133.  
  1134. //-----------------------------------------------------------------------------
  1135. // Name: DrawDotOnGrid()
  1136. // Desc: Draws a dot in the dialog's grid bitmap at the x,y coordinate.
  1137. //-----------------------------------------------------------------------------
  1138. VOID DrawDotOnGrid( HWND hWndGrid, HDC hDC, BOOL bLocalDot, FLOAT fPosX, FLOAT fPosY )
  1139. {
  1140.     RECT     rc;
  1141.     DWORD    dwX;
  1142.     DWORD    dwY;
  1143.     COLORREF crDotColor;
  1144.  
  1145.     // Convert the world space x,y coordinates to pixel coordinates
  1146.     GetClientRect( hWndGrid, &rc );
  1147.     dwX = (DWORD) ( fPosX * (rc.left + rc.right  - 3 ) ) + 1;
  1148.     dwY = (DWORD) ( fPosY * (rc.top  + rc.bottom - 3 ) ) + 1;
  1149.  
  1150.     // Draw a crosshair object in red pixels
  1151.     if( bLocalDot )
  1152.         crDotColor = 0x0000FFFF;
  1153.     else
  1154.         crDotColor = 0x000000FF;
  1155.  
  1156.     SetPixel( hDC, dwX-1, dwY-1, crDotColor );
  1157.     SetPixel( hDC, dwX-1, dwY+0, crDotColor );
  1158.     SetPixel( hDC, dwX-1, dwY+1, crDotColor );
  1159.     SetPixel( hDC, dwX+0, dwY-1, crDotColor );
  1160.     SetPixel( hDC, dwX+0, dwY+0, crDotColor );
  1161.     SetPixel( hDC, dwX+0, dwY+1, crDotColor );
  1162.     SetPixel( hDC, dwX+1, dwY-1, crDotColor );
  1163.     SetPixel( hDC, dwX+1, dwY+0, crDotColor );
  1164.     SetPixel( hDC, dwX+1, dwY+1, crDotColor );
  1165. }
  1166.  
  1167.  
  1168.  
  1169.  
  1170. //-----------------------------------------------------------------------------
  1171. // Name: DirectPlayMessageHandler
  1172. // Desc: Handler for DirectPlay messages.  This function is called by
  1173. //       the DirectPlay message handler pool of threads, so be care of thread
  1174. //       synchronization problems with shared memory
  1175. //-----------------------------------------------------------------------------
  1176. HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, 
  1177.                                          DWORD dwMessageId, 
  1178.                                          PVOID pMsgBuffer )
  1179. {
  1180.     // Try not to stay in this message handler for too long, otherwise
  1181.     // there will be a backlog of data.  The best solution is to 
  1182.     // queue data as it comes in, and then handle it on other threads.
  1183.     
  1184.     // This function is called by the DirectPlay message handler pool of 
  1185.     // threads, so be care of thread synchronization problems with shared memory
  1186.  
  1187.     switch( dwMessageId )
  1188.     {
  1189.         case DPN_MSGID_CREATE_PLAYER:
  1190.         {
  1191.             HRESULT hr;
  1192.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  1193.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;
  1194.  
  1195.             // Create a new and fill in a APP_PLAYER_INFO
  1196.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  1197.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) ); 
  1198.             InitializeCriticalSection( &pPlayerInfo->csPlayer );
  1199.             pPlayerInfo->lRefCount   = 1;
  1200.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  1201.             pPlayerInfo->pt.x        = START_POSITION_X;
  1202.             pPlayerInfo->pt.y        = START_POSITION_Y;
  1203.  
  1204.             // Get the peer info and extract its name
  1205.             DWORD dwSize = 0;
  1206.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  1207.             hr = DPNERR_CONNECTING;
  1208.             
  1209.             // GetPeerInfo might return DPNERR_CONNECTING when connecting, 
  1210.             // so just keep calling it if it does
  1211.             while( hr == DPNERR_CONNECTING ) 
  1212.                 hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );                                
  1213.                 
  1214.             if( hr == DPNERR_BUFFERTOOSMALL )
  1215.             {
  1216.                 pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  1217.                 ZeroMemory( pdpPlayerInfo, dwSize );
  1218.                 pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  1219.                 
  1220.                 hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );
  1221.                 if( SUCCEEDED(hr) )
  1222.                 {
  1223.                     // This stores a extra TCHAR copy of the player name for 
  1224.                     // easier access.  This will be redundent copy since DPlay 
  1225.                     // also keeps a copy of the player name in GetPeerInfo()
  1226.                     DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  1227.                                                        pdpPlayerInfo->pwszName, MAX_PLAYER_NAME );    
  1228.                                                        
  1229.                     // See if this is the local player
  1230.                     if( (pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL) != 0 )
  1231.                     {
  1232.                         g_pPlayerLocal          = pPlayerInfo;
  1233.                         g_pPlayerLocal->pt.x    = START_POSITION_X;
  1234.                         g_pPlayerLocal->pt.y    = START_POSITION_Y;
  1235.                         g_LocalPlayerDPNID      = pCreatePlayerMsg->dpnidPlayer;
  1236.                     }
  1237.                 }
  1238.  
  1239.                 SAFE_DELETE_ARRAY( pdpPlayerInfo );
  1240.             }
  1241.  
  1242.             // Tell DirectPlay to store this pPlayerInfo 
  1243.             // pointer in the pvPlayerContext.
  1244.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  1245.  
  1246.             // Post a message to the dialog thread to update the 
  1247.             // UI.  This keeps the DirectPlay message handler 
  1248.             // from blocking
  1249.             if( g_hDlg != NULL )
  1250.                 PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1251.  
  1252.             break;
  1253.         }
  1254.  
  1255.         case DPN_MSGID_DESTROY_PLAYER:
  1256.         {
  1257.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  1258.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  1259.  
  1260.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  1261.             
  1262.             PLAYER_LOCK();                  // enter player context CS
  1263.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1264.             PLAYER_UNLOCK();                // leave player context CS
  1265.  
  1266.             // Post a message to the dialog thread to update the 
  1267.             // UI.  This keeps the DirectPlay message handler 
  1268.             // from blocking
  1269.             if( g_hDlg != NULL )
  1270.                 PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1271.  
  1272.             // Post a message to the dialog thread to update the 
  1273.             // UI.  This keeps the DirectPlay message handler 
  1274.             // from blocking
  1275.             if( g_hDlg != NULL )
  1276.                 PostMessage( g_hDlg, WM_APP_UPDATE_GRID, 0, 0 );
  1277.             break;
  1278.         }
  1279.  
  1280.         case DPN_MSGID_RECEIVE:
  1281.         {
  1282.             PDPNMSG_RECEIVE pReceiveMsg;
  1283.             pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
  1284.  
  1285.             GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
  1286.             if( pMsg->dwType == GAME_MSGID_PLAYERMOVED )
  1287.             {
  1288.                 GAMEMSG_PLAYERMOVED* pPlayerMovedMsg;
  1289.                 pPlayerMovedMsg = (GAMEMSG_PLAYERMOVED*) pMsg;
  1290.  
  1291.                 APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
  1292.                 EnterCriticalSection( &pPlayerInfo->csPlayer );
  1293.                 pPlayerInfo->pt = pPlayerMovedMsg->pt;
  1294.                 LeaveCriticalSection( &pPlayerInfo->csPlayer );
  1295.  
  1296.                 // Post a message to the dialog thread to update the 
  1297.                 // UI.  This keeps the DirectPlay message handler 
  1298.                 // from blocking
  1299.                 if( g_hDlg != NULL )
  1300.                     PostMessage( g_hDlg, WM_APP_UPDATE_GRID, 0, 0 );
  1301.             }
  1302.             break;
  1303.         }
  1304.  
  1305.         case DPN_MSGID_TERMINATE_SESSION:
  1306.         {
  1307.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  1308.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  1309.  
  1310.             g_hrDialog = DPNERR_CONNECTIONLOST;
  1311.             EndDialog( g_hDlg, 0 );
  1312.             break;
  1313.         }
  1314.     }
  1315.  
  1316.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  1317.     // so it can be informed of messages such as DPN_MSGID_ENUM_HOSTS_RESPONSE.
  1318.     if( g_pNetConnectWizard )
  1319.         return g_pNetConnectWizard->MessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  1320.     
  1321.     return S_OK;
  1322. }
  1323.  
  1324.  
  1325.  
  1326.  
  1327. //-----------------------------------------------------------------------------
  1328. // Name: DirectPlayLobbyMessageHandler
  1329. // Desc: Handler for DirectPlay lobby messages.  This function is called by
  1330. //       the DirectPlay lobby message handler pool of threads, so be careful of 
  1331. //       thread synchronization problems with shared memory
  1332. //-----------------------------------------------------------------------------
  1333. HRESULT WINAPI DirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  1334.                                               DWORD dwMessageId, 
  1335.                                               PVOID pMsgBuffer )
  1336. {
  1337.     switch( dwMessageId )
  1338.     {
  1339.         case DPL_MSGID_CONNECT:
  1340.         {
  1341.             PDPL_MESSAGE_CONNECT pConnectMsg;
  1342.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  1343.  
  1344.             // The CNetConnectWizard will handle this message for us,
  1345.             // so there is nothing we need to do here for this simple
  1346.             // sample.
  1347.             break;
  1348.         }
  1349.  
  1350.         case DPL_MSGID_DISCONNECT:
  1351.         {
  1352.             PDPL_MESSAGE_DISCONNECT pDisconnectMsg;
  1353.             pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)pMsgBuffer;
  1354.  
  1355.             // We should free any data associated with the lobby 
  1356.             // client here, but there is none.
  1357.             break;
  1358.         }
  1359.  
  1360.         case DPL_MSGID_RECEIVE:
  1361.         {
  1362.             PDPL_MESSAGE_RECEIVE pReceiveMsg;
  1363.             pReceiveMsg = (PDPL_MESSAGE_RECEIVE)pMsgBuffer;
  1364.  
  1365.             // The lobby client sent us data.  This sample doesn't
  1366.             // expected data from the client, but it is useful 
  1367.             // for more complex apps.
  1368.             break;
  1369.         }
  1370.  
  1371.         case DPL_MSGID_CONNECTION_SETTINGS:
  1372.         {
  1373.             PDPL_MESSAGE_CONNECTION_SETTINGS pConnectionStatusMsg;
  1374.             pConnectionStatusMsg = (PDPL_MESSAGE_CONNECTION_SETTINGS)pMsgBuffer;
  1375.  
  1376.             // The lobby client has changed the connection settings.  
  1377.             // This simple sample doesn't handle this, but more complex apps may
  1378.             // want to.
  1379.             break;
  1380.         }
  1381.     }
  1382.  
  1383.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  1384.     // so the wizard can be informed of lobby messages such as DPL_MSGID_CONNECT
  1385.     if( g_pNetConnectWizard )
  1386.         return g_pNetConnectWizard->LobbyMessageHandler( pvUserContext, dwMessageId, 
  1387.                                                          pMsgBuffer );
  1388.     
  1389.     return S_OK;
  1390. }
  1391.  
  1392.  
  1393.  
  1394.  
  1395. //-----------------------------------------------------------------------------
  1396. // Name: DirectPlayVoiceServerMessageHandler()
  1397. // Desc: The callback for DirectPlayVoice server messages.  
  1398. //-----------------------------------------------------------------------------
  1399. HRESULT CALLBACK DirectPlayVoiceServerMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  1400.                                                       LPVOID lpMessage )
  1401. {
  1402.     // This simple sample doesn't respond to any server messages
  1403.     return S_OK;
  1404. }
  1405.  
  1406.  
  1407.  
  1408.  
  1409. //-----------------------------------------------------------------------------
  1410. // Name: DirectPlayVoiceClientMessageHandler()
  1411. // Desc: The callback for DirectPlayVoice client messages.  
  1412. //       This handles client messages and updates the UI the whenever a client 
  1413. //       starts or stops talking.  
  1414. //-----------------------------------------------------------------------------
  1415. HRESULT CALLBACK DirectPlayVoiceClientMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  1416.                                                       LPVOID lpMessage )
  1417. {
  1418.     // Try not to stay in this message handler for too long, otherwise
  1419.     // there will be a backlog of data.  The best solution is to 
  1420.     // queue data as it comes in, and then handle it on other threads.
  1421.     
  1422.     // This function is called by the DirectPlay message handler pool of 
  1423.     // threads, so be care of thread synchronization problems with shared memory
  1424.     HRESULT hr;
  1425.     HWND hDlg = (HWND) lpvUserContext;
  1426.  
  1427.     switch( dwMessageType )
  1428.     {
  1429.         case DVMSGID_SESSIONLOST:
  1430.             g_hrDialog = DPNERR_CONNECTIONLOST;
  1431.             EndDialog( g_hDlg, 0 );
  1432.             break;
  1433.  
  1434.         case DVMSGID_CREATEVOICEPLAYER:
  1435.             {
  1436.                 DVMSG_CREATEVOICEPLAYER* pCreateVoicePlayerMsg = (DVMSG_CREATEVOICEPLAYER*) lpMessage;
  1437.                 APP_PLAYER_INFO* pPlayerInfo = NULL;
  1438.  
  1439.                 PLAYER_LOCK(); // enter player context CS
  1440.  
  1441.                 // Get the player context accosicated with this DPNID
  1442.                 hr = g_pDP->GetPlayerContext( pCreateVoicePlayerMsg->dvidPlayer, 
  1443.                                               (LPVOID* const) &pPlayerInfo,
  1444.                                               0);
  1445.  
  1446.                 if( FAILED(hr) || pPlayerInfo == NULL )
  1447.                 {
  1448.                     // The player who sent this may have gone away before this 
  1449.                     // message was handled, so just ignore it
  1450.                     PLAYER_UNLOCK();
  1451.                     break;
  1452.                 }                
  1453.  
  1454.                 // Add and keep an extra reference for the voice context value
  1455.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  1456.                 PLAYER_UNLOCK(); // leave player context CS
  1457.  
  1458.                 // Update the bHalfDuplex flag
  1459.                 pPlayerInfo->bHalfDuplex = ((pCreateVoicePlayerMsg->dwFlags & DVPLAYERCAPS_HALFDUPLEX) != 0);                
  1460.  
  1461.                 // Create a 3D buffer for all remote clients (but not the local one)
  1462.                 if( (DVID) pCreateVoicePlayerMsg->dvidPlayer != g_LocalPlayerDPNID )
  1463.                 {
  1464.                     DWORD dwResult = WaitForSingleObject( g_hSoundInit, 5000 );
  1465.                     if( dwResult == WAIT_TIMEOUT )
  1466.                         return E_FAIL;
  1467.  
  1468.                     LPDIRECTPLAYVOICECLIENT pVoiceClient = g_pNetVoice->GetVoiceClient();
  1469.  
  1470.                     EnterCriticalSection( &pPlayerInfo->csPlayer );
  1471.  
  1472.                     if( FAILED( hr = pVoiceClient->Create3DSoundBuffer( pCreateVoicePlayerMsg->dvidPlayer,
  1473.                                                                         NULL, 0, 0,
  1474.                                                                         &pPlayerInfo->pDSBVoice ) ) )
  1475.                         return DXTRACE_ERR( TEXT("Create3DSoundBuffer"), hr );        
  1476.  
  1477.                     if( FAILED( hr = pPlayerInfo->pDSBVoice->SetMinDistance( 5.0f, DS3D_DEFERRED ) ) )
  1478.                         return DXTRACE_ERR( TEXT("SetMinDistance"), hr );        
  1479.  
  1480.                     if( FAILED( hr = pPlayerInfo->pDSBVoice->SetMaxDistance( 20.0f, DS3D_DEFERRED ) ) )
  1481.                         return DXTRACE_ERR( TEXT("SetMaxDistance"), hr );        
  1482.  
  1483.                     FLOAT f3DPosX = (FLOAT) ( pPlayerInfo->pt.x - START_POSITION_X ) / 10.0f;
  1484.                     FLOAT f3DPosZ = (FLOAT) ( pPlayerInfo->pt.y - START_POSITION_Y ) / 10.0f;
  1485.  
  1486.                     if( FAILED( hr = pPlayerInfo->pDSBVoice->SetPosition( (FLOAT) f3DPosX, 0.0f, f3DPosZ, DS3D_DEFERRED ) ) )
  1487.                         return DXTRACE_ERR( TEXT("SetPosition"), hr );        
  1488.  
  1489.                     if( FAILED( hr = pPlayerInfo->pDSBVoice->SetVelocity( 0.0f, 0.0f, 0.0f, DS3D_DEFERRED ) ) )
  1490.                         return DXTRACE_ERR( TEXT("SetVelocity"), hr );        
  1491.  
  1492.                     LeaveCriticalSection( &pPlayerInfo->csPlayer );
  1493.  
  1494.                     if( FAILED( hr = g_pDSListener->CommitDeferredSettings() ) )
  1495.                         return DXTRACE_ERR( TEXT("CommitDeferredSettings"), hr );        
  1496.                 }
  1497.  
  1498.                 pCreateVoicePlayerMsg->pvPlayerContext = pPlayerInfo;
  1499.  
  1500.                 // Post a message to the dialog thread to update the 
  1501.                 // UI.  This keeps the DirectPlay message handler 
  1502.                 // from blocking
  1503.                 if( hDlg != NULL )
  1504.                     PostMessage( hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1505.  
  1506.                 SendLocalPosition( hDlg );
  1507.             }
  1508.             break;
  1509.  
  1510.         case DVMSGID_DELETEVOICEPLAYER:
  1511.         {
  1512.             DVMSG_DELETEVOICEPLAYER* pMsg = (DVMSG_DELETEVOICEPLAYER*) lpMessage;
  1513.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  1514.  
  1515.             EnterCriticalSection( &pPlayerInfo->csPlayer );
  1516.  
  1517.             // Don't update the dlg if this message is for the local 
  1518.             // client since the dlg will be gone.
  1519.             if( pMsg->dvidPlayer != g_LocalPlayerDPNID )
  1520.             {
  1521.                 // Post a message to the dialog thread to update the 
  1522.                 // UI.  This keeps the DirectPlay message handler 
  1523.                 // from blocking
  1524.                 if( hDlg != NULL )
  1525.                     PostMessage( hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1526.  
  1527.                 // Post a message to the dialog thread to update the 
  1528.                 // UI.  This keeps the DirectPlay message handler 
  1529.                 // from blocking
  1530.                 if( hDlg != NULL )
  1531.                     PostMessage( hDlg, WM_APP_UPDATE_GRID, 0, 0 );
  1532.  
  1533.                 LPDIRECTPLAYVOICECLIENT pVoiceClient = g_pNetVoice->GetVoiceClient();
  1534.                 if( FAILED( hr = pVoiceClient->Delete3DSoundBuffer( pPlayerInfo->dpnidPlayer,
  1535.                                                                     &pPlayerInfo->pDSBVoice ) ) )
  1536.                     DXTRACE_ERR( TEXT("Delete3DSoundBuffer"), hr );        
  1537.             }
  1538.  
  1539.             LeaveCriticalSection( &pPlayerInfo->csPlayer );
  1540.  
  1541.             // Release our extra reference on the player info that we have for the voice
  1542.             // context value.  
  1543.             //
  1544.             PLAYER_LOCK();
  1545.             PLAYER_RELEASE( pPlayerInfo );  
  1546.             PLAYER_UNLOCK();
  1547.             break;
  1548.         }
  1549.  
  1550.         case DVMSGID_HOSTMIGRATED:
  1551.         {
  1552.             DVMSG_HOSTMIGRATED* pMsg = (DVMSG_HOSTMIGRATED*) lpMessage;
  1553.  
  1554.             if( pMsg->pdvServerInterface != NULL )
  1555.             {           
  1556.                 // If we keep the pMsg->pdvServerInterface pointer around, then
  1557.                 // we must AddRef() it.  The CNetVoice::HostMigrate() automatically
  1558.                 // does this for us.
  1559.                 g_pNetVoice->HostMigrate( pMsg->pdvServerInterface );
  1560.  
  1561.                 g_bHostPlayer = TRUE;
  1562.                 SetWindowText( hDlg, TEXT("VoicePosition (Session Host)") );
  1563.             }
  1564.             break;
  1565.         }
  1566.  
  1567.         case DVMSGID_GAINFOCUS:
  1568.         case DVMSGID_LOSTFOCUS:
  1569.         {
  1570.             TCHAR strWindowName[MAX_PATH];
  1571.             wsprintf( strWindowName, TEXT("%s%s%s"), g_strAppName,
  1572.                 (g_bHostPlayer)                      ? TEXT(" (Session Host)") : TEXT(""),
  1573.                 (dwMessageType == DVMSGID_LOSTFOCUS) ? TEXT(" (Focus Lost)") : TEXT("") );
  1574.  
  1575.             SetWindowText( hDlg, strWindowName );
  1576.             break;
  1577.         }
  1578.  
  1579.         case DVMSGID_RECORDSTART:             
  1580.         { 
  1581.             DVMSG_RECORDSTART* pMsg = (DVMSG_RECORDSTART*) lpMessage;
  1582.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext, TRUE );
  1583.             break;
  1584.         }
  1585.         case DVMSGID_RECORDSTOP:             
  1586.         {
  1587.             DVMSG_RECORDSTOP* pMsg = (DVMSG_RECORDSTOP*) lpMessage;
  1588.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext, FALSE );
  1589.             break;
  1590.         }
  1591.         case DVMSGID_PLAYERVOICESTART:
  1592.         {
  1593.             DVMSG_PLAYERVOICESTART* pMsg = (DVMSG_PLAYERVOICESTART*) lpMessage;
  1594.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvPlayerContext, TRUE );
  1595.             break;
  1596.         }
  1597.  
  1598.         case DVMSGID_PLAYERVOICESTOP:
  1599.         {
  1600.             DVMSG_PLAYERVOICESTOP* pMsg = (DVMSG_PLAYERVOICESTOP*) lpMessage;
  1601.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvPlayerContext, FALSE );            
  1602.             break;
  1603.         }
  1604.     }
  1605.  
  1606.     return S_OK;
  1607. }
  1608.  
  1609.  
  1610.  
  1611.  
  1612. //-----------------------------------------------------------------------------
  1613. // Name: SetPlayerTalking()
  1614. // Desc: Set player talking flag
  1615. //-----------------------------------------------------------------------------
  1616. void SetPlayerTalking( APP_PLAYER_INFO* pPlayerInfo, BOOL bTalking )
  1617. {
  1618.     if( pPlayerInfo )
  1619.         pPlayerInfo->bTalking = bTalking;   
  1620. }
  1621.  
  1622.  
  1623.  
  1624.  
  1625. //-----------------------------------------------------------------------------
  1626. // Name: VoiceConfigDlgProc()
  1627. // Desc: Prompt the user for DirectPlayVoice setup options
  1628. //-----------------------------------------------------------------------------
  1629. INT_PTR CALLBACK VoiceConfigDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  1630. {
  1631.     DWORD dwSliderPos;
  1632.  
  1633.     switch( msg ) 
  1634.     {
  1635.         case WM_INITDIALOG:
  1636.             // Set the range on the sliders
  1637.             SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER,       TBM_SETRANGE, FALSE, MAKELONG( 0, 100 ) );
  1638.             SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER,         TBM_SETRANGE, FALSE, MAKELONG( 0, 100 ) );
  1639.             SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER,        TBM_SETRANGE, FALSE, MAKELONG( DVBUFFERQUALITY_MIN, DVBUFFERQUALITY_MAX ) );
  1640.             SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER,    TBM_SETRANGE, FALSE, MAKELONG( DVTHRESHOLD_MIN,  DVTHRESHOLD_MAX ) );
  1641.             SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_SETRANGE, FALSE, MAKELONG( DVBUFFERAGGRESSIVENESS_MIN, DVBUFFERAGGRESSIVENESS_MAX ) );
  1642.  
  1643.             // Setup the dialog based on the globals 
  1644.  
  1645.             // Set the playback controls
  1646.             if( g_dvClientConfig.lPlaybackVolume == DVPLAYBACKVOLUME_DEFAULT )
  1647.             {
  1648.                 CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_DEFAULT );
  1649.             }
  1650.             else
  1651.             {
  1652.                 dwSliderPos = (DWORD) ( ( g_dvClientConfig.lPlaybackVolume - DSBVOLUME_MIN ) * 
  1653.                                           100.0f / (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1654.                 CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_SET );
  1655.                 SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER, TBM_SETPOS, TRUE, dwSliderPos );
  1656.             }
  1657.  
  1658.             // Set the record controls
  1659.             if( g_dvClientConfig.dwFlags & DVCLIENTCONFIG_AUTORECORDVOLUME )
  1660.             {
  1661.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_AUTO );
  1662.             }
  1663.             else if( g_dvClientConfig.lRecordVolume == DVPLAYBACKVOLUME_DEFAULT )
  1664.             {
  1665.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_DEFAULT );
  1666.             }
  1667.             else
  1668.             {
  1669.                 dwSliderPos = (DWORD) ( ( g_dvClientConfig.lRecordVolume - DSBVOLUME_MIN ) * 
  1670.                                           100.0f / (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1671.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_SET );
  1672.                 SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER, TBM_SETPOS, TRUE, dwSliderPos );
  1673.             }
  1674.  
  1675.             // Set the threshold controls
  1676.             if( g_dvClientConfig.dwFlags & DVCLIENTCONFIG_AUTOVOICEACTIVATED )
  1677.             {
  1678.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_AUTO );
  1679.             }
  1680.             else if( g_dvClientConfig.dwThreshold == DVTHRESHOLD_DEFAULT )
  1681.             {
  1682.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_DEFAULT );
  1683.             }
  1684.             else
  1685.             {
  1686.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_SET );
  1687.                 SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwThreshold );
  1688.             }
  1689.  
  1690.             // Set the quality controls
  1691.             if( g_dvClientConfig.dwBufferQuality == DVBUFFERQUALITY_DEFAULT )
  1692.             {
  1693.                 CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_DEFAULT );
  1694.             }
  1695.             else
  1696.             {
  1697.                 CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_SET );
  1698.                 SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwBufferQuality );
  1699.             }
  1700.  
  1701.             // Set the aggressiveness controls
  1702.             if( g_dvClientConfig.dwBufferAggressiveness == DVBUFFERAGGRESSIVENESS_DEFAULT )
  1703.             {
  1704.                 CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_DEFAULT );
  1705.             }
  1706.             else
  1707.             {
  1708.                 CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_SET );
  1709.                 SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwBufferAggressiveness );
  1710.             }
  1711.  
  1712.             if( !g_bHostPlayer || g_bVoiceSessionInProgress )
  1713.             {
  1714.                 // We are are not the host player then disable all the server only options 
  1715.                 EnableWindow( GetDlgItem( hDlg, IDC_COMPRESSION_COMBO ), FALSE );
  1716.                 EnableWindow( GetDlgItem( hDlg, IDC_SESSIONCOMPRESION_GROUP ), FALSE );
  1717.             }
  1718.             else
  1719.             {
  1720.                 VoiceConfigEnumCompressionCodecs( hDlg );   
  1721.                 EnableWindow( GetDlgItem( hDlg, IDCANCEL ), FALSE );
  1722.             }
  1723.  
  1724.             return TRUE;
  1725.  
  1726.         case WM_NOTIFY:
  1727.             #ifndef NM_RELEASEDCAPTURE
  1728.                 #define NM_RELEASEDCAPTURE (NM_FIRST-16)
  1729.             #endif
  1730.             if( ((LPNMHDR) lParam)->code == NM_RELEASEDCAPTURE )
  1731.             {
  1732.                 // If this is a release capture from a slider, then automatically check 
  1733.                 // its 'Set' radio button.
  1734.                 switch( ((LPNMHDR) lParam)->idFrom )
  1735.                 {
  1736.                 case IDC_PLAYBACK_SLIDER:
  1737.                     CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_SET );
  1738.                     break;
  1739.     
  1740.                 case IDC_RECORD_SLIDER:
  1741.                     CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_SET );
  1742.                     break;
  1743.     
  1744.                 case IDC_THRESHOLD_SLIDER:
  1745.                     CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_SET );
  1746.                     break;
  1747.     
  1748.                 case IDC_QUALITY_SLIDER:
  1749.                     CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_SET );
  1750.                     break;
  1751.     
  1752.                 case IDC_AGGRESSIVENESS_SLIDER:
  1753.                     CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_SET );
  1754.                     break;
  1755.                 }
  1756.             }
  1757.             return TRUE;            
  1758.  
  1759.         case WM_COMMAND:
  1760.             switch( LOWORD(wParam) )
  1761.             {
  1762.                 case IDOK:
  1763.                     VoiceConfigDlgOnOK( hDlg );
  1764.                     return TRUE;
  1765.  
  1766.                 case IDCANCEL:
  1767.                     EndDialog( hDlg, IDCANCEL );
  1768.                     return TRUE;
  1769.             }
  1770.             break;
  1771.  
  1772.         case WM_DESTROY:
  1773.         {
  1774.             GUID* pGuid;
  1775.             int nCount = (int)SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETCOUNT, 0, 0 );
  1776.             for( int i=0; i<nCount; i++ )
  1777.             {
  1778.                 pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETITEMDATA, i, 0 );
  1779.                 SAFE_DELETE( pGuid );
  1780.             }
  1781.             break;
  1782.         }
  1783.     }
  1784.  
  1785.     return FALSE; // Didn't handle message
  1786. }
  1787.  
  1788.  
  1789.  
  1790.  
  1791. //-----------------------------------------------------------------------------
  1792. // Name: VoiceConfigEnumCompressionCodecs()
  1793. // Desc: Asks DirectPlayVoice what voice compression codecs are availible
  1794. //       and fills the combo box thier names and GUIDs.
  1795. //-----------------------------------------------------------------------------
  1796. HRESULT VoiceConfigEnumCompressionCodecs( HWND hDlg )
  1797. {
  1798.     LPDIRECTPLAYVOICECLIENT pVoiceClient        = NULL;
  1799.     LPDVCOMPRESSIONINFO     pdvCompressionInfo  = NULL;
  1800.     LPGUID  pGuid         = NULL;
  1801.     LPBYTE  pBuffer       = NULL;
  1802.     DWORD   dwSize        = 0;
  1803.     DWORD   dwNumElements = 0;
  1804.     HWND    hPulldown     = GetDlgItem( hDlg, IDC_COMPRESSION_COMBO );
  1805.     HRESULT hr;
  1806.     LONG    lIndex;
  1807.     LONG    lFirst;
  1808.  
  1809.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  1810.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlayVoiceClient, NULL, 
  1811.                                        CLSCTX_INPROC_SERVER, IID_IDirectPlayVoiceClient, 
  1812.                                        (VOID**) &pVoiceClient ) ) )
  1813.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );        
  1814.  
  1815.     hr = pVoiceClient->GetCompressionTypes( pBuffer, &dwSize, &dwNumElements, 0 );
  1816.     if( hr != DVERR_BUFFERTOOSMALL && FAILED(hr) )
  1817.         return DXTRACE_ERR( TEXT("GetCompressionTypes"), hr );        
  1818.  
  1819.     pBuffer = new BYTE[dwSize];
  1820.     if( FAILED( hr = pVoiceClient->GetCompressionTypes( pBuffer, &dwSize, 
  1821.                                                         &dwNumElements, 0 ) ) )
  1822.         return DXTRACE_ERR( TEXT("GetCompressionTypes"), hr );        
  1823.  
  1824.     SAFE_RELEASE( pVoiceClient );
  1825.     CoUninitialize();
  1826.  
  1827.     pdvCompressionInfo = (LPDVCOMPRESSIONINFO) pBuffer;
  1828.     for( DWORD dwIndex = 0; dwIndex < dwNumElements; dwIndex++ )
  1829.     {
  1830.         TCHAR strName[MAX_PATH];
  1831.  
  1832.         DXUtil_ConvertWideStringToGeneric( strName, pdvCompressionInfo[dwIndex].lpszName );
  1833.         lIndex = (LONG)SendMessage( hPulldown, CB_ADDSTRING, 0, (LPARAM) strName );
  1834.  
  1835.         pGuid = new GUID;
  1836.         (*pGuid) = pdvCompressionInfo[dwIndex].guidType;
  1837.         SendMessage( hPulldown, CB_SETITEMDATA, lIndex, (LPARAM) pGuid );
  1838.  
  1839.         if( pdvCompressionInfo[dwIndex].guidType == DPVCTGUID_SC03 )
  1840.             lFirst = lIndex;
  1841.     }
  1842.  
  1843.     SAFE_DELETE_ARRAY( pBuffer );
  1844.     SendMessage( hPulldown, CB_SETCURSEL, lFirst, 0 );
  1845.  
  1846.     return S_OK;
  1847. }
  1848.  
  1849.  
  1850.  
  1851.  
  1852. //-----------------------------------------------------------------------------
  1853. // Name: VoiceConfigDlgOnOK()
  1854. // Desc: Figure out all the DirectPlayVoice setup params from the dialog box,
  1855. //       and store them in global vars.
  1856. //-----------------------------------------------------------------------------
  1857. VOID VoiceConfigDlgOnOK( HWND hDlg )
  1858. {
  1859.     DWORD dwSliderPos;
  1860.  
  1861.     g_dvClientConfig.dwFlags = 0;
  1862.  
  1863.     // Figure out the playback params
  1864.     if( IsDlgButtonChecked( hDlg, IDC_PLAYBACK_DEFAULT ) )
  1865.     {
  1866.         g_dvClientConfig.lPlaybackVolume = DVPLAYBACKVOLUME_DEFAULT;
  1867.     }
  1868.     else 
  1869.     {
  1870.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER, TBM_GETPOS, 0, 0 );
  1871.         g_dvClientConfig.lPlaybackVolume = DSBVOLUME_MIN + (LONG) ( dwSliderPos / 100.0f * 
  1872.                                                                     (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1873.     }
  1874.  
  1875.     // Figure out the record params
  1876.     if( IsDlgButtonChecked( hDlg, IDC_RECORD_AUTO ) )
  1877.     {
  1878.         g_dvClientConfig.lRecordVolume = 0;
  1879.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_AUTORECORDVOLUME;
  1880.     }
  1881.     else if( IsDlgButtonChecked( hDlg, IDC_RECORD_DEFAULT ) )
  1882.     {
  1883.         g_dvClientConfig.lRecordVolume = DVPLAYBACKVOLUME_DEFAULT;
  1884.     }
  1885.     else 
  1886.     {
  1887.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER, TBM_GETPOS, 0, 0 );
  1888.         g_dvClientConfig.lRecordVolume = DSBVOLUME_MIN + (LONG) ( dwSliderPos / 100.0f * 
  1889.                                                                   (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1890.     }
  1891.  
  1892.     // Figure out the threshold params
  1893.     if( IsDlgButtonChecked( hDlg, IDC_THRESHOLD_AUTO ) )
  1894.     {
  1895.         g_dvClientConfig.dwThreshold = DVTHRESHOLD_UNUSED;
  1896.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_AUTOVOICEACTIVATED;
  1897.     }
  1898.     else if( IsDlgButtonChecked( hDlg, IDC_THRESHOLD_DEFAULT ) )
  1899.     {
  1900.         g_dvClientConfig.dwThreshold = DVTHRESHOLD_DEFAULT;
  1901.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_MANUALVOICEACTIVATED;
  1902.     }
  1903.     else 
  1904.     {
  1905.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER, TBM_GETPOS, 0, 0 );
  1906.         g_dvClientConfig.dwThreshold = dwSliderPos;
  1907.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_MANUALVOICEACTIVATED;
  1908.     }
  1909.  
  1910.     // Figure out the quality params
  1911.     if( IsDlgButtonChecked( hDlg, IDC_QUALITY_DEFAULT ) )
  1912.     {
  1913.         g_dvClientConfig.dwBufferQuality = DVBUFFERQUALITY_DEFAULT;
  1914.     }
  1915.     else 
  1916.     {
  1917.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER, TBM_GETPOS, 0, 0 );
  1918.         g_dvClientConfig.dwBufferQuality = dwSliderPos;
  1919.     }
  1920.  
  1921.     // Figure out the aggressiveness params
  1922.     if( IsDlgButtonChecked( hDlg, IDC_AGGRESSIVENESS_DEFAULT ) )
  1923.     {
  1924.         g_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  1925.     }
  1926.     else 
  1927.     {
  1928.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_GETPOS, 0, 0 );
  1929.         g_dvClientConfig.dwBufferAggressiveness = dwSliderPos;
  1930.     }
  1931.  
  1932.     if( g_bHostPlayer )
  1933.     {
  1934.         // Figure out the compression codec
  1935.         LONG lCurSelection;
  1936.         LPGUID pGuidCT;
  1937.  
  1938.         lCurSelection = (LONG)SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETCURSEL, 0, 0 );
  1939.         if( lCurSelection != CB_ERR )
  1940.         {
  1941.             pGuidCT = (LPGUID) SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, 
  1942.                                                    CB_GETITEMDATA, lCurSelection, 0 );
  1943.             if( pGuidCT != NULL )
  1944.                 g_guidDVSessionCT = (*pGuidCT);
  1945.         }
  1946.     }
  1947.  
  1948.     EndDialog( hDlg, IDOK );
  1949. }
  1950.  
  1951.  
  1952.  
  1953.